#use "types.ml";;
type prog = statement list
and statement = Def of decl | DFun of dfun | Expr of expr
and decl = string * expr
and dfun = string * string list * expr list
and expr = tree list
and tree = Leaf of lexeme | Node of lexeme * expr list
and lexeme = lex * (int * int)
and lex =
    NUM of int
  | FUN of string
  | VAR of string
  | BOOL of bool
  | UNIT of unit
  | STRING of string
type type_lex = TNUM | TFUN | TVAR | TBOOL | TUNIT | TSTRING | TPOL of int
;;
let a = Leaf (NUM 5, (0,1));;
let b = Node (((FUN "plus"), (0,2)), [[Leaf (NUM 6, (0,3)); Leaf (NUM 7, (0,4))]]);;
let c = Node (((FUN "print"), (0,5)), [[Leaf (NUM 45, (0,45))]]);;

let e = [a;b;c];;

let machine_inst e = function
  | ("plus", [NUM a; NUM b]) -> NUM (a+b)
  | ("print", [NUM a]) -> print_int a; UNIT ()


let get_last l = List.hd (List.rev l);;

let rec exec is_f f_args apply_args = function
  | Leaf (VAR v, err) -> VAR v
  | Leaf (e, err) ->  e
  | Node((FUN s, err), args) -> 
            let l = calc [] is_f f_args apply_args args in
             machine_inst err (s, l)
and calc last is_f f_args apply_args = function
  | [] -> last
  | h::t -> calc (List.map (fun x -> exec is_f f_args apply_args x) h) is_f f_args apply_args t
;;
exec false [] [] c;;
let calc_expr is_f f_args apply_args e = 
  List.hd (List.rev (List.map (fun x -> exec is_f f_args apply_args x) e))

;;
calc_expr false [] [] e;;


(*
let rec exec is_f f_args apply_args = function
  | Leaf (VAR v, err) -> VAR v
  | Leaf (e, err) ->  e
  | Node((FUN s, err), args) -> 
      (let fexec = (fun x -> exec is_f f_args apply_args x) in
            let l = List.map fexec args in
              machine_inst err (s, l)
      )
  | _ -> failwith "Syntax error : bad tree."

and f_if fexec e = function
  |  [a;b;c] -> ( match (fexec a) with
                    | BOOL cond -> if cond then fexec b else fexec c
                )

and calc_f f args apply_args l_tree = 
  List.hd (List.rev (List.map (fun x -> exec true args apply_args x) l_tree))
;;

*)
calc_f "d" [] [] e;;
